
#pragma once

#include <stdint.h>
#include <stdlib.h>

#define MD4_DIGEST_SIZE 16
#define MD4_BLOCK_SIZE 64
/* For backwards compatibility */
#define MD4_DATA_SIZE MD4_BLOCK_SIZE

/* Digest is kept internally as 4 32-bit words. */
#define _MD4_DIGEST_LENGTH 4


class CMD4
{
private:
    struct md4_ctx
    {
        uint32_t state[_MD4_DIGEST_LENGTH];
        uint64_t count;			/* Block count */
        uint8_t block[MD4_BLOCK_SIZE];	/* Block buffer */
        unsigned index;			/* Into buffer */
    } ctx_;

    void md4_init();

    void md4_update(size_t length,const uint8_t *data);

    void md4_digest(uint8_t *digest);

    void md4_transform(uint32_t *digest, const uint32_t *data);

    void md4_compress(const void*, const uint8_t *block);
public:
    static const size_t OUTPUT_SIZE         = 16;
    static const size_t BLOCK_SIZE          = 64;
    static const size_t OUTPUT_HMAC_SIZE    = 16;

    CMD4() {
        md4_init();
    }
    CMD4& Write(const unsigned char* data, size_t len) {
        md4_update(len, (uint8_t*)data);
        return *this;
    }
    void Finalize(unsigned char hash[MD4_DIGEST_SIZE]) {
        md4_digest((uint8_t*)hash);
    }
    CMD4& Reset() {
        md4_init();
        return *this;
    }
};